#include "serialportmasterthread.h"
#include <QTime>
#include <QDebug>

SerialPortMasterThread::SerialPortMasterThread(QObject *parent)
    : QThread(parent)
    , m_waitTimeout(0)
    , m_quit(false)
    , m_autoSampling(false)
    , m_autoSamplingPeriod(1000)
{

}

SerialPortMasterThread::~SerialPortMasterThread()
{
    m_mutex.lock();
    m_quit = true;
    m_waitCondition.wakeOne();
    m_mutex.unlock();
    wait();
}

void SerialPortMasterThread::setSerialPortInstance(QSerialPort *portInstance)
{
    this->m_portInstance = portInstance;
}

void SerialPortMasterThread::transaction(QString portName,
                                         qint32 baudRate,
                                         QSerialPort::DataBits dataBits,
                                         QSerialPort::Parity parity,
                                         QSerialPort::StopBits stopBits,
                                         QSerialPort::FlowControl flowControl,
                                         int waitTimeout,
                                         QString request)
{
    this->m_portName = portName;
    this->m_baudRate = baudRate;
    this->m_dataBits = dataBits;
    this->m_parity   = parity;
    this->m_stopBits = stopBits;
    this->m_flowControl = flowControl;
    this->m_waitTimeout = waitTimeout;
    this->m_request  = request;

    if (!isRunning())
    {
        m_quit = false;
        start();
    }
    else
    {
        m_quit = false;
        m_waitCondition.wakeOne();
    }
}

void SerialPortMasterThread::stopTransaction()
{
    if (isRunning())
    {
//        wait();
        qDebug() << "SerialPortMasterThread: Quit auto sampling.";
    }
    else
    {
//        start();
        qDebug() << "SerialPortMasterThread: auto sampling.";
    }
}

void SerialPortMasterThread::setAutoSampling(bool autoSampling)
{
    this->m_autoSampling = autoSampling;
}

void SerialPortMasterThread::setSamplingPeriod(int millisecond)
{
    this->m_autoSamplingPeriod = millisecond;
}

void SerialPortMasterThread::run()
{
    bool currentPortNameChanged = false;

    m_mutex.lock();

    QString currentPortName;
    if (currentPortName != m_portName)
    {
        currentPortName = m_portName;
        currentPortNameChanged = true;
    }
    int currentWaitTimeout = m_waitTimeout;
    QString currentRequest = m_request;
    m_mutex.unlock();
//    QSerialPort serial;

    while (!m_quit)
    {
        qDebug() << "Master Thread: Running.";
        if (currentPortNameChanged)
        {
//            if (m_portInstance->isOpen())
//            {
//                m_portInstance->close();
//            }
            m_portInstance->setPortName(currentPortName);
            m_portInstance->setBaudRate(m_baudRate);
            m_portInstance->setDataBits(m_dataBits);
            m_portInstance->setParity(m_parity);
            m_portInstance->setStopBits(m_stopBits);
            m_portInstance->setFlowControl(m_flowControl);

            if (!m_portInstance->open(QIODevice::ReadWrite))
            {
                emit signalError(tr("Can't open %1, error code %2")
                                 .arg(m_portName).arg(m_portInstance->error()));
                return;
            }
            else
            {
                emit signalSerialPortConnected();
            }
        }
        // write request
        QByteArray requestData = currentRequest.toLocal8Bit();
        m_portInstance->write(requestData);
        if (m_portInstance->waitForBytesWritten(m_waitTimeout))
        {
            // read response
            if (m_portInstance->waitForReadyRead(currentWaitTimeout))
            {
                QByteArray responseData = m_portInstance->readAll();
                while (m_portInstance->waitForReadyRead(10))
                {
                    responseData += m_portInstance->readAll();
                }

                QString response(responseData);

                emit signalResponse(response);
            }
            else
            {
                emit signalTimeout(tr("Wait read response timeout %1")
                                   .arg(QTime::currentTime().toString()));
            }

        } else
        {
            emit signalTimeout(tr("Wait write request timeout %1")
                               .arg(QTime::currentTime().toString()));
        }

        m_mutex.lock();
        if (m_autoSampling)
        {
            msleep(m_autoSamplingPeriod);
        }
        else
        {
            m_waitCondition.wait(&m_mutex);
        }

        if (currentPortName != m_portName)
        {
            currentPortName = m_portName;
            currentPortNameChanged = true;
        }
        else
        {
            currentPortNameChanged = false;
        }
        currentWaitTimeout = m_waitTimeout;
        currentRequest = m_request;
        m_mutex.unlock();
    }
}
